[1] 0.000000 1.609438 1.945910
HiRSE Summer of Programming Languages
Summer 2025
University of Warwick
no developer would mistake R for a programming language
– Simon Urbanek, R Core developer, R Journal 13(2), 22-24, 10.32614/RJ-2021-111
S has a simple goal: To turn ideas into software, quickly and faithfully
– John Chambers, Programming with data: A guide to the S language, ISBN 978-0-387-98503-9.
R is a descendant of S, which was designed as an algorithm interface
Initial design sketch for “The System” by John Chambers, lead developer of S
From: Interfaces, Efficiency and Big Data, useR! 2014
R comes with functions for common tasks in scientific computing, e.g,
Linear algebra
Random number generation and sampling
Optimization
R comes with functions for common tasks in data analytics, e.g,
Reading data
Data manipulation
Statistics and data visualisation
R packages provide additional data structures and functions, e.g.
[1] "xml_document" "xml_node"
Tip
We can use namespacing to access package functions directly, e.g. xml2::read_xml()
The default repository is CRAN, which has >20,000 packages.
We can easily explore interactively when developing a function
A disadvantage of high-level, interpreted languages is they can be slow.
Since R is designed as an algorithm interface, we can speed up bottlenecks with compiled code.
Two R packages make this easier for R programmers:
Suppose we have an R function to compute the Manhattan distance between two points
\[d = \sum^n_i | a_i - b_i| \]
Rcpp::sourceCpp() creates an R wrapper around the C++ code
The quickr::quick() function transpiles R code to Fortran
The best practice for sharing R functions with other R users is to create an R package.
An R package minimally includes
An R package can be created from scratch or from an existing directory
User functions should be documented and exported
groupSort.R
#' Order a Variable by a Grouping Variable
#'
#' Order the elements of a vector by the values of a grouping variable.
#'
#' @param x the variable to order
#' @param g the grouping variable
#' @param decreasing logical: if `TRUE`, order by decreasing values of `g`
#'
#' @returns A variable with the values of `x` sorted by the values of `g`.
#' @export
#' @examples
#' x <- 11:19
#' g <- rep(1:3, length.out = 9)
#' groupSort(x, g)
groupSort <- function(x, g, decreasing = FALSE) {Generate the documentation with devtools::document()
If we put the package in a git repos, those with access can install from R, e.g.
remotes::install_github("hturner/demopkg")
library(demopkg)
groupSort(1:11, rep(1:3, length.out = 9))[1] 1 4 7 2 5 8 3 6 9
Tip
Credentials for private git repos can be set with gitcreds::set()
Create an r-developer.r-universe.dev repo on GitHub and add
Install the r-universe app on GitHub. Then users can install a binary version with
install.packages("demopkg", repos = c(
`R developer` = 'https://r-developer.r-universe.dev',
CRAN = 'https://cloud.r-project.org'))Tip
For private packages use devtools::build(), plus win-builder.r-project.org and/or mac.r-project.org/macbuilder if required.
We can keep an interactive workflow with devtools::load_all()
We can quickly design a Shiny UI with designer::designApp()
We can use the copied code to start creating a Shiny app
app.R
library(shiny)
ui <- bootstrapPage(
title = "Shiny Application",
theme = bslib::bs_theme(4),
h1(
"Group Sort"
),
fileInput(
inputId = "file",
label = "Choose file"
),
inputPanel(
textInput(
inputId = "x",
label = "label"
),
textInput(
inputId = "g",
label = "label"
),
radioButtons(
inputId = "order",
label = "",
choices = c("Increasing", "Decreasing")
)
),
DT::DTOutput(
outputId = "table"
)
)app.R
})
# Reactive value for processed data
processed_data <- reactive({
req(uploaded_data())
data <- uploaded_data()
if (all(c(input$x, input$g) %in% names(data))){
out <- vector(mode = "list")
out[[input$x]] <- demopkg::groupSort(data[[input$x]],
data[[input$g]],
input$order == "Decreasing")
return(as.data.frame(out))
}
})app.R
Tip
Could pass ui to Shiny assistant https://gallery.shinyapps.io/assistant to get an initial draft for server
A Shiny app can be run locally with shiny::runApp("dir/containing/app.R")
Many options, the following are relatively simple and free
| Route | R Packages Source | Hosting |
|---|---|---|
| Posit Cloud Connect | CRAN, Bioconductor, Public GitHub | Cloud server |
| shinylive | CRAN, Bioconductor, R-universe | Self-hosted static HTML, GitHub Pages |
| shinyapps.io | CRAN, Bioconductor, Public/Private GitHub | Cloud server |
Other options are paid (premium versions of shinyapps.io, Posit Cloud Connect) or more work (self-hosted ShinyProxy).
Sign up for shinyapps.io.
Go to Account > Tokens > Show and copy code to run in R
Save app.R in inst/shiny of your R package.
Commit and push.
Install the package from GitHub
Deploy, using sha of git commit in URL
Try it out!
https://supershiny.shinyapps.io/e09f21d4cec5370c2afc656b0c06a6cd399e207d/
Suppose we already had a C++ function to compute the Manhattan distance
\[d = \sum^n_i | a_i - b_i| \]
Within the package source directory run usethis::use_rcpp("Manhattan")
As directed, create demopkg-package.R
Now add the existing C++ code to Manhattan.cpp
Add // [[Rcpp::export]] so that devtools::document() creates an R wrapper
To export the R function, document in the .cpp file
Manhattan.cpp
using namespace Rcpp;
//' Order a Variable by a Grouping Variable
//'
//' Order the elements of a vector by the values of a grouping variable.
//'
//' @param x the variable to order
//' @param g the grouping variable
//' @param decreasing logical: if `TRUE`, order by decreasing values of `g`
//'
//' @returns A variable with the values of `x` sorted by the values of `g`.
//' @export
//' @examples
//' x <- 11:19
//' g <- rep(1:3, length.out = 9)
//' groupSort(x, g)
// [[Rcpp::export]]
double Manhattan(const std::vector<double>& a, const std::vector<double>& b) {R can interface with
R can handle data from the start of a research study…
… to the production of research outputs
Orchestrating all the steps of a workflow in R supports reproducible research.
A data-scientist might do this via
An RSE might contribute via